/*------------------------------------------------------------------------*//**

    @file    FlexamySynth.h
    @brief   FlexamySynth Arduino Library.
    @version Version 1.0 beta 1
    @author  B.O. Love Nystrom.
    
    @mainpage Drive the Fluxamasynth SAM2195 shield.
    
    \b Author: B.O. Love Nystrom.

    Implements an interface for the <a href="http://www.dream.fr/devices.html"><b>
    Atmel/Dream SAM2195 </b></a> synth chip\n present on the 
    <a href="http://shop.moderndevice.com/products/fluxamasynth"><b> 
    Modern Device Fluxamasynth </b></a> shield.\n
    Based on the public Flexamasynth1_NSS library, but the class name
    was changed to FlexamySynth (as in flex a muscle ;) to disambiguate,
    since function semantics and argument order changed in a few places.\n
    <i> I considered calling it DreamSynth, but felt it'd be over the top :)</i>
    
    All documented RPN, NRPN, and SysEx parameter controls are supported.\n
    In all, 100 methods are provided to control the versatile SAM2195,
    covering common MIDI Voice messages, Channel control, RPN-, NRPN-,
    and SysEx Patch Parameter controls, Modulators, Modulation controllers,
    Tuning, Advanced Drum settings, Reverb and Chorus effect control,
    Parametric Equalizer, 3D Surround effect, Clipping control,
    and Master Control.

    In addition, all standard MIDI controllers have symbolic identifiers
    for easy use with the \ref FlexamySynth::controlChange "controlChange"
    method, and several hundred other symbolic identifiers have been defined
    for Patch and Bank names, Reverb and Chorus program names, Modulation
    controller id's, et c.. to make your project code <i>clearly legible</i>.
    
    This code is released to the Open Source community under the new\n
    \ref _lic "NO NONSENSE OPEN SOURCE LICENSE"
    (BSD derivative, pending OSI approval).

    <p><i>Devs: The change log is maintained in FlexamySynth.cpp</i>
    
    <hr><i><pre>Original Fluxamasynth library comment:
    +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
    | Fluxamasynth.cpp - A library to facilitate playing music              |
    |   on the Modern Device Fluxamasynth board.                            |
    | More info is at www.moderndevice.com; refer to                        |
    | "Using the Fluxamasynth Arduino Library" in the DocsWiki.             |
    |                                                                       |
    | This version was derived from the library provided by Modern Devices  |
    | . The NewSoftSerial library is used to communicate with the synth     |
    | . The Constructor has been changed to take the rx and tx pin numbers  |
    |   (and instantiate the NewSoftSerial library);                        |
    |   The default constructor writes to pin 4, and disables receive.      |
    | . A generic function, fluxWrite(...) has been added to write thru     |
    |   to the _port; it may be used alone, or in combination with existing |
    |   library functions (use of fluxWrite must leave the _port capable of |
    |   accepting library commands after, however).                         |
    |                                                                       |
    | This software is in the public domain.                                |
    | Modified 4/2011 R.McGinnis                                            |
    +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
    </pre></i>

    @page _lic NO NONSENSE OPEN SOURCE LICENSE
    <i>(Preliminary text - This license is pending formal review by the OSI)</i>

    Copyright (c) 2012, B.O.Love Nystrom.\n
    All rights reserved.

    Redistribution and use in source and binary forms, with or without modification,
    are permitted provided that the following conditions are met:

    (*) Redistributions of source work must retain the above copyright notice,
        this list of conditions and the following disclaimer.

    (*) Redistributions in binary form must reproduce the above copyright notice,
        this list of conditions and the following disclaimer in the documentation
        and/or other materials provided with the distribution.
       
    (*) Neither the name of Love Nystrom nor the names of any contributors
        may be used to endorse or promote products derived from this work
        without specific prior written permission.

    (*) Except for Your own efforts, You may not demand payment for this work 
        without written permission from the original author(s).

    <b><i> Explanation, 4th clause </i></b><br><i>
        You may e.g. charge for Your own efforts if You include this work in
        derivative works of Your own, or You may extract a reasonable charge for
        the distribution media and mailing cost if You send a disk containing the
        work to a 3rd party, but You may not charge for the work itself without
        written permission from the original author(s). </i>

    \b DISCLAIMER:

    THIS WORK IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    ARE DISCLAIMED.

    IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    THIS WORK, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FlexmySynth_h_inc_
#define _FlexmySynth_h_inc_

#include <Arduino.h>
#include "NewSoftSerial.h"
//#include "PgmChange.h"

// Devs N.B: The comments became a bit finicky due to DoxyGen considerations.
// Hopefully she header remains readable/workable all the same.
// Please be careful with the nested doxygen grouping.
// LN

#define NO_MOD_CONTROLLERS // Agh, there's a firmware bug in SAM2195.
// All 30 'modulation controller' sysex parameter controls are dysfunctional.

//=============================================================================
//! @defgroup _cmac Command byte macros
//! @brief Macros to handle MIDI command (status) bytes.
//! 
//! A MIDI command is indicated by the high bit of the data byte being set.
//! The command byte is a composite of command and channel number. The channel
//! number is the four least significant bits of the command byte. \n
//! Since the high bit denotes a command, it follows that all data values
//! must be restricted to 7 bits.
//@{
#define HI_NIB(b)       ((b) & 0xF0)    //!< Get high nibble.
#define LO_NIB(b)       ((b) & 0x0F)    //!< Get low nibble.

#define MAX_MDATA       0x7F            //!< Max possible MIDI data value.

#define MIDICMD(cmd)    HI_NIB(cmd)     //!< Get MIDI command nibble.
#define MIDICHAN(cmd)   LO_NIB(cmd)     //!< Get MIDI channel nibble.

#ifndef NO_DATA_MASKING
#define MIDIDATA(dat)   ((dat) & 0x7F)  //!< Mask MIDI 7-bit data.
#else   // Save a little code space and execution time at the expense of safety.
#define MIDIDATA(dat)   (dat)           //!< Unmasked MIDI 7-bit data. Careful with that axe!
#endif

#define MIDICOMM(cmd,chan)    byte(MIDICMD(cmd) | MIDICHAN(chan)) //!< Make a MIDI command byte, cmd=8#-F#,chan=0-F (hex).
#define _MIDICOMM(cmd,chan)   byte((cmd) | MIDICHAN(chan)) //!< Make a MIDI command byte ('cmd' not masked).
#define __MIDICOMM(cmd,chan)  byte((cmd) | (chan)) //!< Make a MIDI command byte ('cmd' and ''chan' not masked).
//@}
//! @defgroup _mcmd MIDI Command byte constants
//! Command bytes are defined as channel 1 messages (channel = 0).
//@{
#define ME_NOTEOFF      0x80  //!< {8x kk vv} Note OFF voice message.
#define ME_NOTEON       0x90  //!< {9x kk vv} Note ON voice message.
#define ME_POLYTOUCH    0xA0  //!< {Ax kk vv} Polyphonic key aftertouch. (Not supported by SAM2195).
#define ME_CONTROL      0xB0  //!< {Bx cc vv} Controller change.
#define ME_PROGCHANGE   0xC0  //!< {Cx pp}    Program change.
#define ME_CHANTOUCH    0xD0  //!< {Dx vv}    Channel aftertouch.
#define ME_PITCHBEND    0xE0  //!< {Ex ll hh} Pitchbend change (14bit; ll/hh).
#define ME_SYSTEM       0xF0  /*!< @brief {Fx} System Common / System RealTime messages.
         @details Only SYSEX (F0h/F7h) and RESET (FFh) are supported by SAM2195.
        */
//@}
//! @defgroup _sysx System Exclusive constants
//! Symbolic id's for some common sysex constants.
//@{
#define ME_SYSEX        0xF0  //!< {F0 id dd..dd F7} System Exclusive message.
#define ME_EOX          0xF7  //!< End of System Exclusive {F7}.
#define ME_RESET        0xFF  //!< Reset all receivers to power-up status.

// Some common sysex id's

#define SXID_ROLAND     0x41  //!< Roland sysex id (GS is a Roland standard).
#define SXID_REALTIME   0x7F  //!< RealTime Universal SysEx id.
#define SXID_NON_REALTM 0x7E  //!< Non-RealTime Universal SysEx id.

#define SXM_GS          0x42  //!< GS sysex model id.

#define SX_ALLDEVS      0x7F  //!< All devices (Special device id for sx rt/nrt packets).
#define SX_ALLCHANS     0x7F  //!< All channels (Special channel nr for sx rt/nrt packets).
//@}
//! @defgroup _notv Note values
//! Symbols for note names and velocities.
//@{
//! @defgroup _notn Note names (sharp enharmonics)
//! Symbolic note names to hit the right note (and make your code clear).
//@{
#define NOTE_C    0
#define NOTE_Cs   1
#define NOTE_D    2
#define NOTE_Ds   3
#define NOTE_E    4
#define NOTE_F    5
#define NOTE_Fs   6
#define NOTE_G    7
#define NOTE_Gs   8
#define NOTE_A    9
#define NOTE_As   10
#define NOTE_B    11

#define OCTAVE    12  //!< An octave has 12 semitones.
#define TOP_NOTE  (NOTE_G + OCTAVE*10) //!< Top note in the MIDI note range (127).
//@}
//! @defgroup _velo Velocity constants
//! Symbolic velocity names corresponding to music score note strengths.
//@{
#define VEL_FORTEFORTIS 127   //!< Forte fortizzimo (bombastic)
#define VEL_FORTISSIMO  112	  //!< Fortizzimo (very strong)
#define VEL_FORTE       96	  //!< Forte (strong)
#define VEL_MEZZOFORTE  80	  //!< Mezzo forte (half-strong)
#define VEL_MEZZOPIANO  64	  //!< Mezzo piano (half-calm)
#define VEL_PIANO       48	  //!< Piano (calm)
#define VEL_PIANISSIMO  32	  //!< Pianizzimo (very soft)
#define VEL_PIANOPIANIS 16	  //!< Piano pianizzimo (extremely soft)
#define VEL_MEDIUM      VEL_MEZZOFORTE //!< Half-strong
//@}
//@}

//=============================================================================
//! @defgroup _ctid Controller Id's
//! @brief Symbols for the first data byte of ME_CONTROL messages.
//! 
//! @note SAM2195 support for all of these have not been verified.\n
//! SAM2195 may also support controls not yet defined here (e.g NATIVE, GM/GS).
//@{ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//! @defgroup _ctms Basic controller Id's
//! @brief 7-bit controllers (and 7 MSB of 14-bit controllers).
//@{
#define CT_BANKSELECT   0x00  //!< Bank select, for synth with > 128 patches.
#define CT_WHEEL        0x01  //!< Modulation wheel.
#define CT_BREATHCTRL   0x02  //!< Breath controller.
#define CT_FOOTCTRL     0x04  //!< Foot controller (volume, wahwah &c).
#define CT_PORTATIME    0x05  //!< Portamento time
#define CT_DATAENTRY    0x06  //!< Data entry (for RPN and NRPN).
#define CT_VOLUME       0x07  //!< Channel volume.
#define CT_PAN          0x0A  //!< Channel panoration (L <-> R).
#define CT_EXPRESSION   0x0B  //!< Expression controller.
#define CT_GEN_1        0x10  //!< General purpose 1 continuous controller.
#define CT_GEN_2        0x11  //!< General purpose 2 continuous controller.
#define CT_GEN_3        0x12  //!< General purpose 3 continuous controller.
#define CT_GEN_4        0x13  //!< General purpose 4 continuous controller.
//@}
//! @defgroup _ctls LSB Control Id's
//! @brief ID's for setting the least significant 7 bits of 14 bit controllers.
//! 
//! Add CT_LSB_DIFF to the base id to get the LSB controller Id,
//! or use the predefined constants below.
//@{
#define CT_LSB_DIFF     0x20 //!< Add CT_LSB_DIFF to the control id to get the LSB control Id.

#define CT_BANKSEL_LSB  0x20  //!< Bank select, for synth with > 128 patches.
#define CT_WHEEL_LSB    0x21  //!< Modulation wheel.
#define CT_BREATH_LSB   0x22  //!< Breath controller.
#define CT_FOOT_LSB     0x24  //!< Foot controller (volume,wahwah &c).
#define CT_PORTATIM_LSB 0x25  //!< Portamento time.
#define CT_DATAENT_LSB  0x26  //!< 14bit Data entry (for RPN and NRPN).
#define CT_VOLUME_LSB   0x27  //!< Channel volume.
#define CT_PAN_LSB      0x2A  //!< Channel panoration (L <-> R).
#define CT_EXPRESS_LSB  0x2B  //!< Expression controller.
#define CT_GEN1_LSB     0x30  //!< General purpose 1 continuous controller LSB.
#define CT_GEN2_LSB     0x31  //!< General purpose 2 continuous controller LSB.
#define CT_GEN3_LSB     0x32  //!< General purpose 3 continuous controller LSB.
#define CT_GEN4_LSB     0x33  //!< General purpose 4 continuous controller LSB.
//@}
//! @defgroup _ctsw Switch Controllers
//! @brief Switch things on or off (vv = 7F:On or 00:Off).
//@{
#define CT_DAMPER       0x40  //!< 64 - Damper pedal (Sustain) On/Off.
#define CT_PORTAMENTO   0x41  //!< 65 - Portamento On/Off.
#define CT_SOSTENUTO    0x42  //!< 66 - Sostenuto pedal On/Off.
#define CT_SOFT         0x43  //!< 67 - Soft pedal On/Off.
#define CT_REVERBPROG   0x50  //!< 80 - Set reverb program, 0-7. (SAM, Global i.e CH0)
#define CT_CHORUSPROG   0x51  //!< 81 - Set chorus program, 0-7. (SAM, Global i.e CH0)
#define CT_GEN_SW3      0x52  //!< 82 - General purpose switch 3.
#define CT_GEN_SW4      0x53  //!< 83 - General purpose switch 4.
//@}
//! @defgroup _ctef Effect Send Controllers
//! @brief Controls effect send levels (vv = 0-127).
//@{
#define CT_REVERB       0x5B  //!< 91 - Reverb depth.
#define CT_TREMOLO      0x5C  //!< 92 - Tremolo depth.
#define CT_CHORUS       0x5D  //!< 93 - Chorus depth.
#define CT_DETUNE       0x5E  //!< 94 - Detune amount.
#define CT_PHASER       0x5F  //!< 95 - Phaser depth.
//@}
//! @defgroup _ctdt RPN- and NRPN Controls
//! @brief Registered- and NonRegistered Parameter Number data entry controllers.
//@{
#define CT_DATAINC      0x60  //!< 96 - Value +1.
#define CT_DATADEC      0x61  //!< 97 - Value -1.
#define CT_NONREG_LSB   0x62  //!< 98 - NRPN (non-registered parameter number) LSB.
#define CT_NONREG_MSB   0x63  //!< 99 - NRPN MSB (high part of number).
#define CT_REG_LSB      0x64  //!< 100 - RPN (registered parameter number) LSB.
#define CT_REG_MSB      0x65  //!< 101 - RPN MSB (most significant byte).
//@}
//! @defgroup _ctcm Channel Mode Messages
//! @brief Special controllers affecting the synth operation mode.
//@{
#define CT_ALLSOUNDOFF  0x78  //!< 120 - Silence all outputs.
#define CT_RESETCTRL    0x79  //!< 121 - Reset all controllers to defaults.
#define CT_LOCALCTRL    0x7A  //!< 122 - Local control On/Off (vv=$7F/$00).
#define CT_ALLNOTESOFF  0x7B  //!< 123 - Turn off all oscillators.
#define CT_OMNI_OFF     0x7C  //!< 124 - Omni mode Off (vv=0).
#define CT_OMNI_ON      0x7D  //!< 125 - Omni mode On (vv=0).
#define CT_MONO_ON      0x7E  //!< 126 - Mono mode On (Poly Off) (vv=Nr chans(Omni off) or 0(Omni on)).
#define CT_POLY_ON      0x7F  //!< 127 - Poly mode On (Mono Off) (vv=0).
//@}
//@} endgroup _ctid

//=============================================================================
//! @defgroup _ctdv Control Data Values
//! Constants and macros for control data.
//@{ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//! @defgroup _ctdb Common values
//! @brief Symbolic constants for common control values.
//@{ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#define CTV_SWITCHON     0x7F    //!< ON (3rd byte of midi switch controller)
#define CTV_SWITCHOFF    0x00    //!< OFF (3rd byte of midi switch controller)

#define CTV_CENTER       0x40    //!< Neutral (center) value for 7bit bipolar ctrl values
#define CTV_CENTER14     0x2000  //!< Neutral (center) value for 14bit bipolar ctrl values
#define CTV_MAX14        0x3FFF  //!< Maximum 14 bit control value
#define CTV_MASK14       0x3FFF  //!< Mask 14 bits of word value

#define CTV_NOPITCH14    CTV_CENTER14 //!< Center pitchbend value (14 bits)
#define CTV_NOPITCH      CTV_CENTER   //!< High 7 bits of center pitchbend value

//@} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//! @defgroup _ctdm Data Value Macros
//! @brief Macros to handle 14 bit 'big' controller values, e.g pitch bend.
//@{ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//! Make a 14-bit control value from low/high bytes.
#define CTV_VAL14(lo,hi)    word(((hi & 0x7F) << 7)| (lo & 0x7F))

//! Make a 14-bit control value, *no masking*.
#define _CTV_VAL14(lo,hi)   word((hi << 7)| lo )

//! Extract low 7 bits of a 14-bit control value.
#define CTV_LOW(val)        byte(val & 0x7F)

//! Extract high 7 bits of a 14-bit control value.
#define CTV_HIGH(val)       byte((val >> 7) & 0x7F)

//! Extract high 7 bits of a 14-bit control value, *no masking*.
#define _CTV_HIGH(val)      byte(val >> 7)

//@}
//@} endgroup _ctdv

//=============================================================================
//! @defgroup _helper Control Value Conversion Functions
//! @brief Convert human comprehensible values to MIDI control values.
//@{ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//! @defgroup _bipo Bipolar Value Conversion
//! @brief Convert bipolar values to biased MIDI controls.
//! 
//! You can use these functions to convert signed bipolar values
//! (+-63/+-8191) to standard biased MIDI 7bit/14bit control values.
//! To avoid messing up MIDI control value compatibility by using signed
//! control values, class methods expect standard (biased) control values
//! for "bipolar" controllers, e.g. pitch bend, tuning, or transpose.
//@{ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

byte ccByte( int8_t Value );
    /**<
    @brief Convert a signed 8-bit value to a biased MIDI control value.
    @param Value  Signed 8-bit value, -64..+63.
    @return Return a biased control value, 0-127.
    */

word ccWord( short Value );
    /**<
    @brief Convert a signed 14-bit value to a biased MIDI control value.
    @details The equivalent of ((Value + CTV_CENTER14) & CT_MASK14).
    @param Value Signed 14-bit value, -8192..+8191.
    @return Return a biased control value, 0x0000-0x3FFF.
    */
    
//@} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//! @defgroup _eqcv Equalizer Frequency Control Values.
//! @brief Convert corner frequency in Hz to corresponding SAM2195 control value.
//@{ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

byte EqBassCtrl( word Hz );
    /**<
    @brief Compute an Equalizer BASS frequency parameter.
    @param Hz Corner frequency, in Hz.
    @return Returns an appropriate control value 0-127.
    @sa \ref FlexamySynth::setEqFrequency, \ref EqBassHz
    */

byte EqMidCtrl( word Hz );
    /**<
    @brief Compute an Equalizer MID frequency parameter.
    @param Hz  Corner frequency, in Hz.
    @return Returns an appropriate control value 0-127.
    @sa \ref FlexamySynth::setEqFrequency, \ref EqMidHz
    */
    
byte EqTrebleCtrl( word Hz );
    /**<
    @brief Compute an Equalizer TREBLE frequency parameter.
    @param Hz  Corner frequency, in Hz.
    @return Returns an appropriate control value 0-127.
    @sa \ref FlexamySynth::setEqFrequency, \ref EqTrebleHz
    */
    
//@} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//! @defgroup _eqbc Equalizer Control back-convert
//! @brief Convert EQ control value back to Hz.
//! @details (Can also tell you how/if your set frequency was quantized.)
//@{ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

word EqBassHz( byte ctrlVal );
    /**<
    @brief Compute a frequency from a control value. 
    @details The inverse of \ref EqBassCtrl.
    @param ctrlVal Control value, 0-127 (7Fh).
    */

word EqMidHz( byte ctrlVal );
    /**<
    @brief Compute a frequency from a control value.
    @details The inverse of \ref EqMidCtrl.
    @param ctrlVal Control value, 0-127 (7Fh).
    */

word EqTrebleHz( byte ctrlVal );
    /**<
    @brief Compute a frequency from a control value.
    @details The inverse of \ref EqTrebleCtrl.
    @param ctrlVal Control value, 0-127 (7Fh).
    */
    
//@}
//@} endgroup _helper
//+----------------------------------------------------------------------------
//! @class FlexamySynth
//! @brief Atmel/Dream SAM2195 Fluxamasynth interface class.
//! 
//! All documented RPN, NRPN, and SysEx parameter controls are supported.\n
//! In all, 100 methods are provided to control the versatile SAM2195,
//! covering common MIDI Voice messages, Channel control, RPN-, NRPN-,
//! and SysEx Patch Parameter controls, Modulators, Modulation controllers,
//! Tuning, Advanced Drum settings, Reverb and Chorus effect control,
//! Parametric Equalizer, 3D Surround effect, Clipping control,
//! and Master Control.
//+----------------------------------------------------------------------------

class FlexamySynth {     // <-- DreamFlux ;)
protected:
    NewSoftSerial _port; //!< Communications driver
    bool _portOpen;      //!< Initialization flag
    byte _runStat;       //!< MIDI running status
    byte _effects;       //!< Effect enable flags

    void _sendPartParameter( byte Part, byte ParmNr, byte CtrlVal );
    /**<
    @brief Send a 'Patch Part Parameter' group 1*h block.
    @param Part    Part nr or midi channel.
    @param ParmNr  LSB of parameter index. (Address e.g. 40h 1*h ParmNr).
    @param CtrlVal Control value, 0-7Fh.
    */

    void _sendModParameter( byte Channel, byte ParmNr, byte CtrlVal );
    /**<
    @brief Send Modulation control (patch part param 2*h group).
    @param Channel Midi channel.
    @param ParmNr  LSB of parameter index. (Address e.g. 40h 2*h ParmNr).
    @param CtrlVal Control value, 0-7Fh.
    */

    void _sendDreamControl( byte FuncNr, byte Value );
    /**<
    @brief Send a Dream NRPN 37**h parameter.
    @param FuncNr LSB of NRPN nr.
    @param Value  Control value.
    */

public: //---------------------------------------------------------------------

//! @defgroup _ctor FlexamySynth Constructors
//! @brief Initialize an object instance.
//@{

    FlexamySynth( void );
    /**<
    @brief Default constructors sets NewSoftSerial TX = pin 4, RX inhibit.
    */

    FlexamySynth( byte rxPin, byte txPin );
    /**<
    @brief Construct with a specific setup for NewSoftSerial.
    @param rxPin  Pin nr to receive on, 255 = Inhibit receive.
    @param txPin  Pin nr to send on.
    */

//@} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//! @defgroup _common FlexamySynth Common class methods
//! General subroutines used by other methods.
//@{ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    void begin();
    /**<
    @brief Open NewSoftSerial port, & c.
    @note You must call begin() before you can call any other methods.
    */
        
    void fluxWrite( byte B );
    /**<
    @brief Send one byte to Fluxamasynth
    @param B  The byte to send
    */
        
    void fluxWrite( byte *Buf, word Count );
    /**<
    @brief Send a byte sequence to Fluxamasynth,
    @param Buf   Point to an array of bytes to send.
    @param Count Nr of bytes to send
    */
        
    void writeMidiCmd( byte Cmd );  
    /**<
    @brief Send a MIDI command.
    @details Manages MIDI running status (saves communication bandwidth).
    @param Cmd  A midi command byte. High nibble=Cmd, low nibble=Channel.
    */
        
    void sendParameterData( byte *Data, word Length ); 
    /**<
    @brief Send a SysEx DT1 Patch Parameter packet
    @param Data  The block must begin with 2 LSB parameter address,
      followed by the parameter data (commonly 1 byte).
      The MSB parameter address (40h) is hard coded in the function.
    @param  Length  Nr of bytes in the Data block.
    */

//@} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//! @defgroup _channel SAM2195 Channel control
//! These methods control a single MIDI channel.
//@{ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    void noteOn( byte Channel, byte Key, byte Velocity );
    /**<
    @brief Send a Note On message. [9* kk vv]
    @param Channel  MIDI channel, 0-15
    @param Key      MIDI key, 0-127
    @param Velocity Key strike force, 0-127
    */

    void noteOff( byte Channel, byte Key );
    /**<
    @brief Send a Note Off message. [8* kk vv]
    @param Channel MIDI channel, 0-15
    @param Key     MIDI key, 0-127
    */
    
    void controlChange( byte Channel, byte CtrlNr, byte Value );
    /**<
    @brief Send a Control Change message [B* cc vv].
    @param Channel MIDI channel, 0-15
    @param CtrlNr  Controller nr, 0-127, e.g \ref CT_VOLUME, \ref CT_CHORUS.
    @param Value   Control value, 0-127
    */

    void setControlValue( byte Channel, byte CtrlNr, word Value );
    /**<
    @brief Send a big value (14 bit) Control Change message [B* cc hh cc+20h ll].
    @param Channel MIDI channel, 0-15
    @param CtrlNr  Controller nr, 0-127, e.g \ref CT_WHEEL, \ref CT_EXPRESSION.
    @param Value   Control value, 0-127
    */
    
    void programChange( byte Channel, byte Patch );
    /**<
    @brief Send a Program Change message [C* pp].

    You can use the program id's from \ref PgmChange.h to easily set the sound you want.
    @param Channel MIDI channel, 0-15
    @param Patch   Patch (program) nr, 0-127
    */

    void programChange( byte Channel, byte Bank, byte Patch );
    /**<
    @brief Combine Bank Select and Program Change messages.
    @param Channel MIDI channel, 0-15
    @param Bank    Patch bank, 0 or 127
    @param Patch   Patch (program) nr, 0-127
    @sa \ref setPatchBank, \ref programChange( byte Channel, byte Patch )
    */

    void setPatchBank( byte Channel, byte Bank );
    /**<
    @brief Select Patch Bank for this channel.

    SAM2195 has two patch banks, #0 (GM) and #127 (MT-32).
    You can use the bank id's from \ref PgmChange.h to get the sounds you want.
    @param Channel MIDI channel, 0-15
    @param Bank    Patch bank, 0 or 127
    */

    void setPatchBank( byte Bank );
    /**<
    @brief Select a patch bank for all channels except 9 (drums).
    @param Bank  Patch bank, 0 or 127
    @sa \ref setPatchBank( byte Channel, byte Bank )
    */
    
    void polyAftertouch( byte Channel, byte Key, byte Value );
    /**<
    @brief Send a polyphonic aftertouch [PAF] message [A* kk vv].
    @param Channel MIDI channel, 0-15
    @param Key     MIDI key, 0-127
    @param Value   Force (pressure) value, 0-127
    @note PAF controls are ignored by SAM2195, but declared here for completeness.
    */

    void channelAftertouch( byte Channel, byte Value );
    /**<
    @brief Send a channel aftertouch [CAF] message [D* vv].
    @param Channel MIDI channel, 0-15
    @param Value   Force (pressure) value, 0-127
    */
    
    void pitchBend( byte Channel, word Bend );
    /**<
    @brief Send a pitch bend message [E* ll hh].
    @param Channel MIDI channel, 0-15
    @param Bend    Bend amount, biased bipolar, 0h - 2000h - 3FFFh
    */
    
    void setBendRange( byte Channel, byte Range );
    /**<
    @brief Set pitch bend range.
    @param Channel MIDI channel, 0-15
    @param Range   Bend range (semitones), 0-127, default 2.
    */
    
    void RPN_Control( byte Channel, byte rpnHi, byte rpnLo, byte Data );
    /**<
    @brief Send a Registered Parameter Number control message.
    @param Channel MIDI channel, 0-15
    @param rpnHi   High part of RPN number
    @param rpnLo   Low part of RPN number
    @param Data    Control value
    */
    
    void NRPN_Control( byte Channel, byte nrpnHi, byte nrpnLo, byte Data );
    /**<
    @brief Send a Non-Registered Parameter Number control message.
    @param Channel MIDI channel, 0-15
    @param nrpnHi  High part of NRPN number
    @param nrpnLo  Low part of NRPN number
    @param Data    Control value
    */
    
    void dataEntry( byte Channel, byte Data );
    /**<
    @brief Provide (more) data to RPN and NRPN.
    @param Channel MIDI channel, 0-15
    @param Data    Control value
    */

    //!\cond nodoc
    #ifdef HAVE_14B_CONTROLLER
    void RPN_ControlW( byte Channel, byte rpnHi, byte rpnLo, word Data ); // 14bit
    void NRPN_ControlW( byte Channel, byte rpnHi, byte rpnLo, word Data ); // 14bit
    void dataEntryW( byte Channel, word Data ); // 14bit
    #endif //!\endcond

    void setChannelVolume( byte Channel, byte Level );
    /**<
    @brief Set channel volume.
    @param Channel MIDI channel, 0-15
    @param Level   Channel volume, 0-127
    @note This is the same as controlChange( Channel, CT_VOLUME, Level ).
    */

    void allNotesOff( byte Channel );
    /**<
    @brief Turn off all oscillators.
    @param Channel MIDI channel, 0-15
    @note This is the same as controlChange( Channel, CT_ALLNOTESOFF, 7Fh ).
    */
    
    void setPartChannel( byte Part, byte Channel );
    /**<
    @brief Allow assigning several parts to a single MIDI channel, or mute a part.
    <pre>
    Default, Part   : 0         1-9  10-15
    Default, Channel: 9(DRUMS)  0-8  10-15
    </pre>
    @param Part    Part nr, 0-15
    @param Channel Midi channel, 0-15
    */
    
    void setPartMode( byte Part, boolean Drums );
    /**<
    @brief  Allows you to setup multiple drum channels.
    @param Part  Part nr, 0-15
    @param Drums True for drum mode, false for sound mode.
    @see See also: \ref setPartChannel.
    */
    
    void setVoiceReserve( byte *CountTable );
    /**<
    @brief Set reserved voices.
    @param CountTable Table must contain 16 bytes with voice counts.
    */
    
    void assignCC1Controller( byte Channel, byte CtrlNr );
    /**<
    @brief Assign a controller to CC1.
    @details Allows mapping a controller, e.g \ref CT_EXPRESSION, to the generic
     \ref MOD_CC1 controller, for use with the SAM2195 modulation control.
    @param Channel MIDI channel, 0-15.
    @param CtrlNr  Controller nr, default is 0x10 (\ref CT_GEN_1).
    */

    void assignCC2Controller( byte Channel, byte CtrlNr );
    /**<
    @brief Assign a controller to CC2.
    @details Allows mapping a controller, e.g \ref CT_GEN_1, to the generic
     \ref MOD_CC2 controller, for use with the SAM2195 modulation control.
    @param Channel MIDI channel, 0-15
    @param CtrlNr  Controller nr, default is 0x11 (\ref CT_GEN_2).
    */

    // Reverb & Chorus Send 
    // Note: Reverb/Chorus effect parameters are global, further down.

    void setReverbSend( byte Channel, byte Level );
    /**<
    @brief Set channel reverb send level.
    @param Channel MIDI channel, 0-15
    @param Level   Send level, 0-127.
    */
    
    void setChorusSend( byte Channel, byte Level );
    /**<
    @brief Set channel chorus send level.
    @param Channel MIDI channel, 0-15
    @param Level   Send level, 0-127.
    */

//@} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/** @defgroup _tuning SAM2195 Tuning functions
    @brief Synth master tuning and channel tune/detune.
    
    In MIDI, an entire device is tuned by either sending RPN#1
    (Channel Fine Tuning) to all MIDI channels being used, or by sending
    a System Exclusive Master Tune.

    RPN#1 allows tuning to be specified in steps of approximately 0.012 cents
    (to be precise, 100/8192 cent), and System Exclusive Master Tune allows
    tuning in steps of 0.1 cent. One cent is 1/100th of a semitone.
    The values of RPN#1 (Channel Fine Tuning) and System Exclusive Master Tune
    are added together to determine the actual pitch sounded by each Part.

    Frequently used tuning values for your reference:
    <pre>
    +~~~~~~~~~+~~~~~~~~+~~~~~~~~~~~~~~~~~~~~~~~+~~~~~~~~~~~~~~~~~~~~+
    | Hz @ A4 | cents  |         RPN#1         |  Sys.Ex. 40 00 00  |
    +~~~~~~~~~+~~~~~~~~+~~~~~~~~~~~~~~~~~~~~~~~+~~~~~~~~~~~~~~~~~~~~+
    |  445.0  | +19.56 | (+1603) 2643 4C:43 4C | (+196) 00 04 0C 04 |
    |  444.0  | +15.67 | (+1283) 2503 4A:03 4A | (+157) 00 04 09 0D |
    |  443.0  | +11.76 | (+ 964) 23C4 47:44 47 | (+118) 00 04 07 06 |
    |  442.0  | + 7.85 | (+ 643) 2283 45:03 45 | (+ 79) 00 04 04 0F |
    |  441.0  | + 3.93 | (+ 322) 2142 42:42 42 | (+ 39) 00 04 02 07 |
    |  440.0  |   0    | (  0  ) 2000 40:00 40 | (   0) 00 04 00 00 |
    |  439.0  | - 3.94 | (- 323) 1EBD 3D:3D 3D | (- 39) 00 03 0D 09 |
    |  438.0  | - 7.89 | (- 646) 1D7A 3A:7A 3A | (- 79) 00 03 0B 01 |
    +~~~~~~~~~+~~~~~~~~+~~~~~~~~~~~~~~~~~~~~~~~+~~~~~~~~~~~~~~~~~~~~+
    </pre>
    @note SAM2195 doesn't support 14 bit RPN controls, so the tuning step of
    RPN#1 is just 100/64 (1.56) cent. SysEx master tune is better for tuning.
    That is, use \ref setEzMasterTuning to tune the synth to other instruments.
    However, RPN#1 is also useful for various effects, e.g layering a
    detuned duplicate voice for a fatter sound, or whatever..
    */
//@{ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    void setTranspose( byte Channel, byte SemiCtrl );
    /**<
    @brief Set channel transpose.
    @param Channel  MIDI channel, 0-15
    @param SemiCtrl Nr of semitones, 00h-40h-7Fh, where 40h == no transpose.
    */

    void setTuning( byte Channel, byte CentsCtrl );
    /**<
    @brief Set channel tuning, +-100 cent in steps of 100/64 cent.
    @param Channel   MIDI channel, 0-15
    @param CentsCtrl Cents, 00h-40h-7Fh, where 40h == no detune.
    */
        
    //!\cond nodoc
    #ifdef HAVE_14B_CONTROLLER
    void setFineTuning( byte Channel, word CentsCtrl ); // Tuning +-100 cent, step 100/8192 cent
    friend int8_t tuningCents( word CtrlVal ); // Biased 14b ctrl value to bipolar cents
    friend word tuningCtrlValue( int8_t Cents ); // Bipolar cents to biased 14b ctrl value
    #endif //!\endcond
    
    void setScaleTuning( byte Channel, byte* TuningTable );
    /**<
    @brief Allows the use of exotic scales, Pytagorean or whatever..
    @param Channel - MIDI channel, 0-15
    @param TuningTable - An array of 12 bytes with relative pitch
    for each of the scale semitones.
    */
        
    // Master tuning (global, but declared here for the sake of doxygen grouping)
    
    void setMasterTranspose( byte Semitones );
    /**<
    @brief Set master transpose for the whole synth.
    @param Semitones - Semitones up/down, 00h-40h-7Fh (40h == no transpose).
    */
    
    void setMasterTuning( word CtrlValue );
    /**<
    @brief Set master tuning for the synth.
    @details Master tuning, -100.0 to +100.0 cents, in steps of 0.1 cent.
    @param CtrlValue - Raw biased 14b ctrl value, 0018h-0400h-07E8h (400h == no detune).
    */

    void setEzMasterTuning( short DeciCent );
    /**<
    @brief Set easy master tuning for the synth.
    @param DeciCent - Tuning value, +-100.0 cent in steps of 0.1 cent.
    */

//@} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//! @defgroup _drum SAM2195 Advanced Drum Settings
//! @brief Allow precise control of the drum synth mix and effects.
//@{ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    //! @brief Change the pitch of a single drum.

    void setDrumPitch ( 
        byte Channel,   //!< MIDI channel, 0-15
        byte DrumNr,    //!< Drum nr, see \ref PgmChange.h
        byte Semitone   //!< Semitones up or down, 00h-40h-7Fh (40h == no detune).
        );
    
    //! @brief Advanced drum mix settings.

    void setDrumMix ( 
        byte Channel,   //!< MIDI channel, 0-15
        byte DrumNr,    //!< Drum nr, see \ref PgmChange.h
        byte Level,     //!< Sound level, 0-127.
        byte Pan,       //!< Pan setting, 00h-40h-7Fh (40h == center).
        byte Reverb,    //!< Reverb send, 0-127.
        byte Chorus     //!< Chorus send, 0-127.
        );

//@} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//! @defgroup _modl SAM2195 Modulators
//!
//! These methods govern how the modulators affect the timbre of the currently
//! selected patch on one of the 16 MIDI channels.
//@{ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    void setVelocitySlope( byte Channel, byte Slope );
    /**<
    @brief Change the slope of the velocity curve.
    @param Channel  MIDI channel, 0-15
    @param Slope    Velocity curve slope, 0-127.
    */
    
    void setVelocityOffset( byte Channel, byte Offset );
    /**<
    @brief Change the offset of the velocity curve.
    @param Channel  MIDI channel, 0-15
    @param Offset   Velocity curve offset, 0-127.
    */

    void setVibrato( byte Channel, byte Rate, byte Depth, byte Delay );
    /**<
    @brief Set all three vibrato parameters for the channel. 
    @param Channel  MIDI channel, 0-15
    @param Rate     Vibrato rate, 0-127.
    @param Depth    Vibrato depth, 0-127.
    @param Delay    Vibrato delay, 0-127.
    */
    
    void setVibratoRate( byte Channel, byte Rate );
    /**<
    @brief Set vibrato rate. 
    @param Channel  MIDI channel, 0-15
    @param Rate     Vibrato rate, 0-127.
    */

    void setVibratoDepth( byte Channel, byte Depth );
    /**<
    @brief Set vibrato depth. 
    @param Channel  MIDI channel, 0-15
    @param Depth    Vibrato depth, 0-127.
    */
    
    void setVibratoDelay( byte Channel, byte Delay );
    /**<
    @brief Set vibrato delay. 
    @param Channel  MIDI channel, 0-15
    @param Delay    Vibrato delay, 0-127.
    */

    void setTvFilter( byte Channel, byte CutoffFreq, byte Resonance );
    /**<
    @brief Change Time-Variant Filter settings for the channel.
    @param Channel    MIDI channel, 0-15
    @param CutoffFreq Filter corner frequency, 0-127
    @param Resonance  Filter resonance, 0-127
    */
    
    void setTvfCutoff( byte Channel, byte CutoffFreq );
    /**<
    @brief Set cutoff frequency of the time variant filter.
    @param Channel    MIDI channel, 0-15
    @param CutoffFreq Filter corner frequency, 0-127
    */
    
    void setTvfResonance( byte Channel, byte Resonance );
    /**<
    @brief Set resonance of the time variant filter.
    @param Channel    MIDI channel, 0-15
    @param Resonance  Filter resonance, 0-127
    */

    void setEnvelope( byte Channel, byte Attack, byte Decay, byte Release );
    /**<
    @brief Change all three settings for the ADR envelope generator.
    @param Channel  MIDI channel, 0-15
    @param Attack   Initial peak rise time of envelope, 0-127
    @param Decay    Falloff time to sustain of envelope, 0-127
    @param Release  Key release fadeout time, 0-127
    */
    
    void setEnvAttack( byte Channel, byte Attack );
    /**<
    @brief Change envelope attack time for the channel.
    @param Channel  MIDI channel, 0-15
    @param Attack   Initial peak rise time of envelope, 0-127
    */
    
    void setEnvDecay( byte Channel, byte Decay );
    /**<
    @brief Change envelope decay time for the channel.
    @param Channel  MIDI channel, 0-15
    @param Decay    Falloff time to sustain of envelope, 0-127
    */
    
    void setEnvRelease( byte Channel, byte Release );
    /**<
    @brief Change envelope release time for the channel.
    @param Channel  MIDI channel, 0-15
    @param Release  Key release fadeout time, 0-127
    */

    void setLfoRate( byte CtrlVal );
    /**<
    @brief Set LFO rate (frequency) for all channels.
    @param CtrlVal  LFO rate control, 0-127 (default==64)
    @note The LFO rate is global for all 16 channels.
    */

#ifndef NO_MOD_CONTROLLERS
//@} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//! @defgroup _modc SAM2195 Modulation Controllers
//! @brief Setup five different modulation controllers.
//!
//! These methods govern how the modulation controllers affect the modulators
//! in the currently selected patch on a channel.
//@{ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    #define MOD_WHEEL   0x00  //!< Modulation wheel controller.
    #define MOD_BENDER  0x10  //!< Pitchbend controller.
    #define MOD_CAF     0x20  //!< [C]hannel [AF]tertouch control.
    #define MOD_CC1     0x40  //!< Programmable custom control 1. See \ref FlexamySynth::assignCC1Controller
    #define MOD_CC2     0x50  //!< Programmable custom control 2. See \ref FlexamySynth::assignCC2Controller
    
    void setModPitchDepth( byte Controller, byte Channel, byte SemiCtrl );
    /**<
    @brief Set pitch depth control for a modulator.
    @param Controller Controller ID, one of the MOD_nnn constants.
    @param Channel  MIDI channel, 0-15
    @param SemiCtrl Semitones pitch depth.
    */
    
    void setModTvfCutoff( byte Controller, byte Channel, byte CtrlVal );
    /**<
    @brief Set TVF cutoff frequency for a modulator.
    @param Controller Controller ID, one of the MOD_nnn constants.
    @param Channel  MIDI channel, 0-15
    @param CtrlVal  Control value, 0-127
    */
    
    void setModAmplitude( byte Controller, byte Channel, byte CtrlVal );
    /**<
    @brief Set amplitude control for a modulator.
    @param Controller Controller ID, one of the MOD_nnn constants.
    @param Channel  MIDI channel, 0-15
    @param CtrlVal  Control value, 0-127
    */
    
    void setModLfoPitchDepth( byte Controller, byte Channel, byte CtrlVal );
    /**<
    @brief Set LFO pitch depth control for a modulator.
    @param Controller Controller ID, one of the MOD_nnn constants.
    @param Channel  MIDI channel, 0-15
    @param CtrlVal  Control value, 0-127
    */
    
    void setModLfoTvfDepth( byte Controller, byte Channel, byte CtrlVal );
    /**<
    @brief Set time variant filter LFO control depth for a modulator.
    @param Controller Controller ID, one of the MOD_nnn constants.
    @param Channel  MIDI channel, 0-15
    @param CtrlVal  Control value, 0-127
    */
    
    void setModLfoTvaDepth( byte Controller, byte Channel, byte CtrlVal );
    /**<
    @brief Set time variant amplitude LFO control depth for a modulator.
    @param Controller Controller ID, one of the MOD_nnn constants.
    @param Channel  MIDI channel, 0-15
    @param CtrlVal  Control value, 0-127
    */

#endif //ndef NO_MOD_CONTROLLERS
//@} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//! @defgroup _master SAM2195 Master Control
//! These methods control the whole synthesizer.
//@{ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    void midiReset();
    /**<
    @brief Standard MIDI reset (FFh). Silence oscillators &c. 
    */

    void GM_Reset();
    /**<
    @brief Reset device to GM mode and set default control values, &c.
    */

    void GS_Reset();
    /**<
    @brief Reset device to GS mode, and set default control values, &c.
    */

    void setMasterVolume( byte Level );
    /**<
    @brief Set GM master volume.
    @param Level  Master volume, 0-127.
    */

    void GS_MasterVolume( byte Level );
    /**<
    @brief Set GS master volume. 
    @param Level  Master volume, 0-127.
    */

    void GS_MasterPan( byte Pan );
    /**<
    @brief Set master left/right panoration
    @param Pan  Panning value, 00h-40h-7Fh (40h == center).
    */

//@} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//! @defgroup _verb SAM2195 Reverb Effect Control
//! @brief Reverb parameters (global effect unit, not per channel)
//@{ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    void setReverbLevel( byte MasterLevel );
    /**<
    @brief Set master reverb return level.
    @param MasterLevel  Reverb level, 0-127
    */
    
    //! @brief Set all the reverb parameters (in the global effects unit).
    
    void setReverb (
        byte Program,       //!< Reverb program, one of the REV_nnn constants.
        byte Time,          //!< Reverb time, 0-127.
        byte Feedback,      //!< Reverb feedback, 0-127. Only valid for DELAY and PANDELAY.
        byte Character = 4  //!< Reverb algorithm, 0-7.
        );

    #define REV_ROOM1       0  //!< Room 1 reverb program.
    #define REV_ROOM2       1  //!< Room 2 reverb program.
    #define REV_ROOM3       2  //!< Room 3 reverb program.
    #define REV_HALL1       3  //!< Hall 1 reverb program.
    #define REV_HALL2       4  //!< Hall 2 reverb program.
    #define REV_PLATE       5  //!< Plate reverb program.
    #define REV_DELAY       6  //!< Delay reverb program.
    #define REV_PANDELAY    7  //!< Panning delay reverb program.

    #define REV_DEFLEVEL  0x64 //!< Default reverb master level
    #define REV_DEFCHAR   0x04 //!< Default reverb character

    void setReverbProgram( byte Program );
    /**<
    @brief Change reverb program.
    @param Program  Reverb program, one of the REV_nnn constants.
    */

    void setReverbTime( byte Time );
    /**<
    @brief Change reverb time.
    @param Time  Reverb time, 0-127.
    */

    void setReverbFeedback( byte Feedback );
    /**<
    @brief Change reverb feedback. Only valid for REV_DELAY and REV_PANDELAY.
    @param Feedback  Reverb feedback, 0-127.
    */

    void setReverbCharacter( byte Character );
    /**<
    @brief Change reverb sound character (reverb algorithm).
    @param Character  Reverb algorithm, 0-7.
    */

//@} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//! @defgroup _chor SAM2195 Chorus Effect Control
//! @brief Chorus parameters (global effect unit, not per channel)
//@{ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    void setChorusLevel( byte MasterLevel );
    /**<
    @brief Set master chorus return level.
    @param MasterLevel  Reverb level, 0-127
    */

    //! @brief Setup chorus parameters for the synth effects unit. 

    void setChorus ( 
        byte Program,   //!< Chorus program, one of the CHO_nnn constants.
        byte Delay,     //!< Chorus delay time.
        byte Feedback,  //!< Chorus feedback amount.
        byte Rate,      //!< Chorus LFO rate.
        byte Depth      //!< Chorus modulation depth.
        );
    #define CHO_CHORUS1     0  //!< Chorus 1 program.
    #define CHO_CHORUS2     1  //!< Chorus 2 program.
    #define CHO_CHORUS3     2  //!< Chorus 3 program.
    #define CHO_CHORUS4     3  //!< Chorus 4 program.
    #define CHO_FEEDBACK    4  //!< Feedback chorus program.
    #define CHO_FLANGER     5  //!< Flanger program.
    #define CHO_SHORTDELAY  6  //!< Short delay chorus program.
    #define CHO_FBDELAY     7  //!< Feedback delay chorus program.

    void setChorusProgram( byte Program );
    /**<
    @brief Setup chorus parameters for the synth effects unit.
    @param Program  Chorus program, one of the CHO_nnn constants.
    */

    void setChorusDelay( byte Delay );
    /**<
    @brief Setup chorus parameters for the synth effects unit.
    @param Delay  Chorus delay time.
    */

    void setChorusFeedback( byte Feedback );
    /**<
    @brief Setup chorus parameters for the synth effects unit.
    @param Feedback  Chorus feedback amount.
    */

    void setChorusRate( byte Rate );
    /**< 
    @brief Setup chorus parameters for the synth effects unit.
    @param Rate  Chorus LFO rate.
    */

    void setChorusDepth( byte Depth );
    /**<
    @brief Setup chorus parameters for the synth effects unit.
    @param Depth  Chorus modulation depth.
    */

//@} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//! @defgroup _dream Special DREAM Functions
//! @brief Special SAM2195 NRPN 37**h controls.
//! @details <i>These are 37**h controls that didn't fit in some other category.</i>
//@{ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    void enableEffects( byte Flags );
    /**< 
    @brief Enable/disable individual effects.
    @param Flags  A combination of EF_nnn flags, or EF_RESET.
    
    @note By default, all effect units are on. If you disable any unit,
    or change the equalizer config, the chorus is turned off.
    EF_RESET (45h) is the only way to turn it back on.
    Value 45h will reset all. This is the only way to restore the default setting,
    and turn the chorus on again. The firmware will be stopped during reset procedure
    (about 50 ms), before being ready to process MIDI messages again
    */
    #define EF_EQ_2BAND  0x02  //!< 2 band eq, polyphony -4 voice
    #define EF_EQ_4BAND  0x03  //!< 4 band eq, polyphony -8 voice
    #define EF_SURROUND  0x08  //!< Surround on, polyphony -2 voice
    #define EF_REVERB    0x20  //!< Reverb on, polyphony -13 voice
    #define EF_ALL       EF_REVERB| EF_SURROUND| EF_EQ_4BAND //!< Combine all EF flags.

    #define EF_RESET     0x45  //!< Reverb ON, Chorus ON, Surround ON, 4-Band Equalizer.

    void restartEffects();
    /**<
    @brief Restart effects. Same as enableEffects( EF_RESET ).
    */

    void enableReverb( boolean On );
    /**< 
    @brief Enable or disable the reverb unit.
    @param On  True to turn on, false to turn off.
    */

    void enableSurround( boolean On );
    /**< 
    @brief Enable or disable the 3D surround unit.
    @param On True to turn on, false to turn off.
    */

    void setEqualizerMode( byte revMode );
    /**< 
    @brief Change equalizer mode. 4 band, 2 band, or Off.
    @param revMode One of EF_EQ_2BAND, or EF_EQ_4BAND. Zero turns the reverb off.
    */

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Soft/hard clipping and sound Output level
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    void setClippingMode( byte Mode );
    /**<
    @brief Set clipping mode.
    @param Mode  One of SOFT_CLIP, or HARD_CLIP.
    */
    #define SOFT_CLIP   0x00  //!< Soft clipping mode
    #define HARD_CLIP   0x7F  //!< Hard clipping mode

    void setOutputLevel( byte Level ); 
    /**< 
    @brief Set SAM2195 master volume.
    @param Level  Output level, 0-127.
    */

//@} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//! @defgroup _eq SAM2195 Equalizer Control
//! @brief Change settings for the parametric equalizer.
//!
//! The low-band filter frequency is 0-4700 Hz, the two mid-band
//! filters are 0-4200 Hz, and the high-band filter 0-18750 Hz.
//! (The actual lower frequency limit of each band is as yet undetermined,
//! so it's uncertain what frequency control value 0 correspond to).
//@{ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    #define EQ_BASS     0   //!< EQ Band 0: 0-4.7 kHz, +-12 dB [default 444Hz(0Ch) +6dB(60h)]
    #define EQ_LOWMID   1   //!< EQ Band 1: 0-4.2 kHz, +-12 dB [default 893Hz(1Bh) 0dB(40h)]
    #define EQ_HIGHMID  2   //!< EQ Band 2: 0-4.2 kHz, +-12 dB [default 3770kHz(72h) 0dB(40h)]
    #define EQ_TREBLE   3   //!< EQ Band 3: 0-18.75 kHz, +-12 dB [default 9449Hz(40h) +6dB(60h)]

    void setEqualizer( byte BandNr, byte Freq, byte Gain );
    /**< 
    @brief Change settings for one of 4 parametric equalizers.
    
    \e Example: setEqualizer( EQ_BASS, EqBassCtrl( 220 ), 0x60 );
    @param BandNr Equalizer nr, 0-3, or one of the \ref EQ_BASS "EQ_nnn" values.
    @param Freq Corner frequency, 0-127. See \ref setEqFrequency.
    @param Gain Gain,+-12dB, 00h-40h-7Fh (40h == 0dB).
    */

    void setEqFrequency( byte BandNr, byte Frequency );
    /**< 
    @brief Change corner frequency for one of 4 parametric equalizers.
        
    The \ref EqBassCtrl, \ref EqMidCtrl, and \ref EqTrebleCtrl
    functions compute an appropriate Frequency value for the filter, 
    given an argument in Hz. EqBassCtrl is used for the EQ_BASS filter,
    EqMidCtrl for EQ_LOWMID and EQ_HIGHMID, and EqTrebleCtrl for EQ_TREBLE.
    @param BandNr Equalizer nr, 0-3, or one of the \ref EQ_BASS "EQ_nnn" values.
    @param Frequency Corner frequency, 0-127.
    */

    void setEqGain( byte BandNr, byte Gain );
    /**< 
    @brief Change gain for one of 4 parametric equalizers.
        
    Set the filter gain +-12 dB, in steps of 0.1875 dB.
    You can use the \ref EQL_P_12dB "EQL_nnn" constants for common gain values.
    @param BandNr Equalizer nr, 0-3, or one of the \ref EQ_BASS "EQ_nnn" values.
    @param Gain   Gain +-12dB, 00h-40h-7Fh (40h == 0dB).
    */
    #define EQL_P_12dB  0x7F  //!< +12 dB EQ gain
    #define EQL_P_9dB   0x70  //!<  +9 dB EQ gain
    #define EQL_P_6dB   0x60  //!<  +6 dB EQ gain
    #define EQL_P_3dB   0x50  //!<  +3 dB EQ gain
    #define EQL_0dB     0x40  //!<   0 dB EQ gain
    #define EQL_M_3dB   0x30  //!<  -3 dB EQ gain
    #define EQL_M_6dB   0x20  //!<  -6 dB EQ gain
    #define EQL_M_9dB   0x10  //!<  -9 dB EQ gain
    #define EQL_M_12dB  0x00  //!< -12 dB EQ gain

//@} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//! @defgroup _3d SAM2195 3D Surround Control
//! @brief Set volume, time, and input mode of the 3D surround unit.
//@{ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    void setSurroundVolume( byte Level );
    /**<
    @brief Set 3D surround level.
    @param Level  Surround level, 0-127.
    */

    void setSurroundDelay( byte Time );
    /**<
    @brief Set 3D surround time.
    @param Time  Surround delay, 0-127.
    */

    void surroundMonoIn( boolean Mono );
    /**<
    @brief Switch 3D surround input between mono and stereo mode.
    @param Mono  True for mono, false for stereo input.
    */

//@} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//! @defgroup _post SAM2195 Post Processing Control
//! @brief   Signal routing (post processing on/off).
//! @details Post processing effects are the equalizer and 3D surround unit.
//@{ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    void postprocGeneralMidi( boolean On );
    /**< 
    @brief Turn GM post processing on or off.
    @param On  True to turn on, false to turn off.
    */

    void postprocReverbChorus( boolean On );
    /**<
    @brief Turn post processing on or off for the reverb and chorus unit.
    @param On  True to turn on, false to turn off.
    */

//@} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//! @defgroup _gmctrl SAM2195 Special GM Controls
//! @brief General Midi controls (SAM2195 NRPN 0x37## controls)
//! 
//! @note At the time of this writing, it is undetermined if the basic\n
//! GM controls in SAM2195 support individual channels or are global.\n
//! Both implementations are provided so you may find out.\n
//! Please report your findings to the lib distribution page.
//@{ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    // Channel 0 (Midi cmd byte == 0xB0)
    
    void GM_ReverbSend( byte Level );
    /**< 
    @brief General Midi reverb send.
    @param Level  Send level, 0-127, default 64.
    */

    void GM_ChorusSend( byte Level );
    /**<
    @brief General Midi chorus send.
    @param Level  Send level, 0-127, default 64.
    */

    void GM_Volume( byte Level );
    /**<
    @brief General Midi volume.
    @param Level  Output level, 0-127.
    */

    void GM_Pan( byte Pan );
    /**< 
    @brief General Midi panoration.
    @param Pan  Pan position, 00h-40h-7Fh (40h == center).
    */

    // Channel specific (Midi cmd byte == 0xB#)
    
    void GM_ReverbSend( byte Channel, byte Level );
    /**<
    @brief General Midi reverb send.
    @param Channel MIDI channel, 0-15.
    @param Level   Send level, 0-127, default 64.
    */

    void GM_ChorusSend( byte Channel, byte Level );
    /**< 
    @brief General Midi chorus send.
    @param Channel MIDI channel, 0-15.
    @param Level   Send level, 0-127, default 64.
    */

    void GM_Volume( byte Channel, byte Level );
    /**<
    @brief General Midi volume.
    @param Channel MIDI channel, 0-15.
    @param Level   Output level, 0-127.
    */

    void GM_Pan( byte Channel, byte Pan );
    /**<
    @brief General Midi panoration.
    @param Channel MIDI channel, 0-15.
    @param Pan     Pan position, 0-127 (40h == center).
    */

//@} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//! @defgroup _misc SAM2195 Miscellaneous
//! @brief Rarely used methods
//@{ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    void setSysExModuleId( byte Id );
    /**<
    @brief Change the module's system exclusive identifier.
    @details Only needed if you have a clashing module id on the same MIDI chain.
    @param Id  New module id, 00h-7Fh (default 00h).
    @note The \ref sendParameterData method currently don't support changing the id.
    */
        
    void runSelfTest();
    /**<
    @brief Built-in auto-test program. Refer to the chip document.
        
    Sine waveforms at different frequencies are output to the
    DAC to indicate the test in progress. If PASS frequency is detected,
    it means that part is OK. \n
    On chip RAM: 1.18 kHz, On chip ROM: 876 Hz, PASS 295 Hz.
    */
//@}
};

//-----------------------------------------------------------------------------
#endif //ndef _FlexmySynth_h_inc_
